import {
  ValuePairDic,
} from './valuePair';

export class Dictionary {
  protected table: {
    [key: string]: ValuePairDic | null | undefined;
  }

  public constructor(tableInit: Dictionary.TDicTableInitial = []) {
    this.table = {};

    for (let val of tableInit) {
      this.set(val[0], val[1]);
    }
  }

  public hasKey(key: Dictionary.TDicTableKey) {
    const value = this.table[key]; 
    return value !== null && value !== undefined;
  }

  public set(key: Dictionary.TDicTableKey, value: any): boolean {
    if (value !== null && value !== undefined) {
      this.table[key] = new ValuePairDic(key, value);
      return true;
    } else {
      return false;
    }
  }

  public remove(key: Dictionary.TDicTableKey) {
    if (this.hasKey(key)) {
      delete this.table[key];
      return true;
    } else {
      return false;
    }
  }

  public get(key: Dictionary.TDicTableKey) {
    return this.table[key];
  }

  public entries() {
    const tableV = Object.values(this.table);
    const entries: ValuePairDic[] = [];

    for (let valuePair of tableV) {
      if (valuePair) {
        entries.push(valuePair);
      }
    }

    return entries;
  }

  public keys() {
    return this.entries().map(item => item.key);
  }

  public values() {
    return this.entries().map(item => item.value);
  }

  public forEach(cb: (key: Dictionary.TDicTableKey, value: any) => any) {
    const valuePairs = this.entries();

    for (let i = 0; i < valuePairs.length; i++) {
      const value = valuePairs[i];
      cb(value.key, value.value);
    }
  }

  public size() {
    return Object.keys(this.table).length;
  }

  public isEmpty() {
    return this.size() === 0;
  }

  public clear() {
    this.table = {};
  }

  public toString() {
    if (this.isEmpty()) {
      return '';
    } else {
      const entries = this.entries();
      let str = `${entries[0].toString()}`;
      
      for (let i = 1; i < entries.length; i++) {
        str = `${str},${entries[i]}`;
      }

      return str;
    }
  }
}